package org.goldenport.g3.messages

import scala.collection.mutable.ArrayBuffer
import java.io._
import java.net.URL
import org.goldenport.g3.{G3Message, G3Control, G3AgentContext}
import org.goldenport.g3.messages.cli.CliCommand
import org.goldenport.g3.events.Exceptioned

/**
 * @since   Jun. 10, 2010
 * @version Oct. 10, 2010
 * @author  ASAMI, Tomoharu
 */
trait MsgCommon {
  implicit def isSuccessMessageAction(elem: Any): Boolean = {
    !elem.isInstanceOf[Exceptioned]
  }
}

object MsgSeq {
  def apply(messages: G3Message*) = new MsgSeq(messages: _*)
}

object MsgAnd extends MsgCommon {
  def apply(messages: G3Message*) = new MsgSeqAnd(messages: _*)
}

object MsgOr extends MsgCommon {
  def apply(messages: G3Message*) = new MsgSeqOr(messages: _*)
}

object MsgSeqAnd extends MsgCommon {
  def apply(messages: G3Message*) = new MsgSeqAnd(messages: _*)
}

object MsgSeqOr extends MsgCommon {
  def apply(messages: G3Message*) = new MsgSeqOr(messages: _*)
}

object MsgPara {
  def apply(messages: G3Message*) = new MsgPara(messages: _*)
}

object MsgParaAnd extends MsgCommon {
  def apply(messages: G3Message*) = new MsgSeqAnd(messages: _*)
}

object MsgParaOr extends MsgCommon {
  def apply(messages: G3Message*) = new MsgSeqOr(messages: _*)
}

class MsgSeq(messages: G3Message*) extends G3Control(messages: _*) {
  def copy(msg: G3Message*): G3Message = {
    new MsgSeq(msg: _*)
  }
}

class MsgSeqAnd(messages: G3Message*)(implicit isSuccessMessageAction: Any => Boolean) extends G3Control(messages: _*) {
  def copy(msg: G3Message*): G3Message = {
    new MsgSeqAnd(msg: _*)
  }

  override def eval[B](f: G3Message => B): List[B] = {
    val buf = new ArrayBuffer[B]
    for (msg <- messages) {
      msg match {
        case control: G3Control => {
          val elems = control.eval(f)
          buf ++= elems
          if (!elems.exists(isSuccessMessageAction)) {
            return buf.toList
          }
        }
        case _ => {
          val elem = f(msg)
          buf += elem
          if (!isSuccessMessageAction(elem)) {
            return buf.toList
          }
        }
      }
    }
    return buf.toList
  }
}

class MsgSeqOr(messages: G3Message*)(implicit isSuccessMessageAction: Any => Boolean) extends G3Control(messages: _*) {
  def copy(msg: G3Message*): G3Message = {
    new MsgSeqOr(msg: _*)
  }

  override def eval[B](f: G3Message => B): List[B] = {
    val buf = new ArrayBuffer[B]
    for (msg <- messages) {
      msg match {
        case control: G3Control => {
          val elems = control.eval(f)
          buf ++= elems
          if (elems.exists(isSuccessMessageAction)) {
            return buf.toList
          }
        }
        case _ => {
          val elem = f(msg)
          buf += elem
          if (isSuccessMessageAction(elem)) {
            return buf.toList
          }
        }
      }
    }
    return buf.toList
  }
}

class MsgPara(messages: G3Message*) extends G3Control(messages: _*) {
  def copy(msg: G3Message*): G3Message = {
    new MsgPara(msg: _*)
  }
}

class MsgParaAnd(messages: G3Message*) extends G3Control(messages: _*) {
  def copy(msg: G3Message*): G3Message = {
    new MsgParaAnd(msg: _*)
  }
}

class MsgParaOr(messages: G3Message*) extends G3Control(messages: _*) {
  def copy(msg: G3Message*): G3Message = {
    new MsgParaOr(msg: _*)
  }
}

// 2010-09-18
object Ping extends Ping {
  def apply() = new Ping
}

class Ping extends G3Control {
  def copy(msg: G3Message*): G3Message = this
}

// 2010-09-27
object MsgFold {
  def apply(messages: G3Message*) = new MsgFold(messages: _*)
}

class MsgFold(messages: G3Message*) extends G3Control(messages: _*) {
  def copy(msg: G3Message*): G3Message = {
    new MsgFold(msg: _*)
  }
}

// 2010-09-27
object Args extends Args

object Arg {
  def apply(index: Int) = new Arg(index)
}

trait MsgVar extends G3Message {
  def toString(ctx: G3AgentContext): String = {
    normalize(ctx).mkString
  }
}

class Args extends G3Message with MsgVar {
  override def normalize(ctx: G3AgentContext): Seq[G3Message] = {
    ctx.signal match {
      case Some(signal: CliCommand) => List(Value(signal.request))
      case Some(signal) => List(Value(signal))
      case None => Nil
    }
  }
}

class Arg(index: Int) extends G3Message with MsgVar {
  override def normalize(ctx: G3AgentContext): Seq[G3Message] = {
    def get_element(elems: List[_]): Seq[G3Message] = {
      val r = elems.lift(index) match {
        case Some(v) => List(Value(v))
        case None => Nil
      }
//      println("Arg index elements = " + elems + " -> " + r)
      r
    }

//    println("Arg index = " + ctx.signal)
    ctx.signal match {
      case Some(signal: CliCommand) => get_element(signal.request)
      case Some(signal: List[_]) => get_element(signal)
      case Some(signal) => Nil
      case None => Nil
    }
  }
}

object Value {
  def apply(value: Any) = new Value(value)
}

class Value(val value: Any) extends G3Message {
  override def toString() = value.toString
}
